package org.lc.kcjxzj.textcheck;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.stereotype.Component;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.seg.common.Term;

/**
 * 改进的Jaccard相似度算法实现类
 * 
 * 改进点：
 * 1. 使用HanLP进行专业分词
 * 2. 添加分词缓存机制
 * 3. 使用词频权重
 * 4. 优化集合运算性能
 */
@Component
public class JaccardSimilarity implements SimilarityCalculator {

    // 分词结果缓存
    private static final Map<String, List<Term>> segmentationCache = new ConcurrentHashMap<>();
    
    // 词性权重
    private static final Map<String, Double> POS_WEIGHT = new HashMap<>();
    
    static {
        POS_WEIGHT.put("n", 1.0);   // 普通名词
        POS_WEIGHT.put("v", 0.8);   // 普通动词
        POS_WEIGHT.put("vn", 1.0);  // 动名词
        POS_WEIGHT.put("nz", 1.2);  // 专有名词
        POS_WEIGHT.put("a", 0.8);   // 形容词
        POS_WEIGHT.put("d", 0.5);   // 副词
        POS_WEIGHT.put("p", 0.3);   // 介词
        POS_WEIGHT.put("c", 0.3);   // 连词
        POS_WEIGHT.put("w", 0.0);   // 标点符号
    }

    @Override
    public double calculate(String text1, String text2) {
        if (text1 == null || text2 == null) {
            return 0.0;
        }

        if (text1.isEmpty() && text2.isEmpty()) {
            return 1.0;
        }
        if (text1.isEmpty() || text2.isEmpty()) {
            return 0.0;
        }

        // 获取加权词项集合
        Map<String, Double> weightedSet1 = getWeightedTerms(text1);
        Map<String, Double> weightedSet2 = getWeightedTerms(text2);

        if (weightedSet1.isEmpty() && weightedSet2.isEmpty()) {
            return 1.0;
        }
        if (weightedSet1.isEmpty() || weightedSet2.isEmpty()) {
            return 0.0;
        }

        // 计算交集权重和
        double intersectionWeight = calculateIntersectionWeight(weightedSet1, weightedSet2);
        
        // 计算并集权重和
        double unionWeight = calculateUnionWeight(weightedSet1, weightedSet2);

        if (unionWeight == 0.0) {
            return 0.0;
        }

        // 计算基础Jaccard系数
        double baseJaccard = intersectionWeight / unionWeight;

        // 根据文本长度调整相似度
        return adjustSimilarity(baseJaccard, text1.length(), text2.length());
    }

    /**
     * 获取文本的加权词项集合
     */
    private Map<String, Double> getWeightedTerms(String text) {
        // 从缓存获取分词结果
        List<Term> terms = segmentationCache.computeIfAbsent(text, k -> HanLP.segment(text));
        
        Map<String, Double> weightedTerms = new HashMap<>();
        
        for (Term term : terms) {
            String word = term.word.toLowerCase();
            String nature = term.nature.toString();
            
            // 获取词性权重
            double posWeight = POS_WEIGHT.getOrDefault(
                nature.length() > 1 ? nature.substring(0, 1) : nature,
                0.5
            );
            
            // 计算词长度权重
            double lengthWeight = calculateLengthWeight(word);
            
            // 合并权重并累加
            weightedTerms.merge(word, posWeight * lengthWeight, Double::sum);
        }
        
        return weightedTerms;
    }

    /**
     * 计算词长度权重
     */
    private double calculateLengthWeight(String word) {
        if (word.length() <= 1) return 0.8;
        if (word.length() == 2) return 1.0;
        if (word.length() == 3) return 1.2;
        return 1.5;
    }

    /**
     * 计算交集权重和
     */
    private double calculateIntersectionWeight(Map<String, Double> set1, Map<String, Double> set2) {
        return set1.entrySet().stream()
            .filter(entry -> set2.containsKey(entry.getKey()))
            .mapToDouble(entry -> Math.min(entry.getValue(), set2.get(entry.getKey())))
            .sum();
    }

    /**
     * 计算并集权重和
     */
    private double calculateUnionWeight(Map<String, Double> set1, Map<String, Double> set2) {
        Map<String, Double> union = new HashMap<>(set1);
        
        // 合并set2中的权重
        set2.forEach((key, value) -> 
            union.merge(key, value, Math::max)
        );
        
        return union.values().stream().mapToDouble(Double::doubleValue).sum();
    }

    /**
     * 根据文本长度调整相似度
     */
    private double adjustSimilarity(double similarity, int len1, int len2) {
        // 计算长度比例
        double lengthRatio = (double) Math.min(len1, len2) / Math.max(len1, len2);
        
        // 短文本需要更严格的相似度要求
        if (Math.min(len1, len2) < 10) {
            return similarity * (0.7 + 0.3 * lengthRatio);
        }
        
        // 长文本适当提升相似度
        if (Math.max(len1, len2) > 100) {
            return similarity * (0.9 + 0.1 * lengthRatio);
        }
        
        return similarity * (0.8 + 0.2 * lengthRatio);
    }

    /**
     * 清理指定文本的分词缓存
     */
    public void clearCache(String text) {
        if (text != null) {
            segmentationCache.remove(text);
        }
    }

    /**
     * 清理所有分词缓存
     */
    public void clearAllCache() {
        segmentationCache.clear();
    }
}